package com.xc.pay.weixin.util;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

/**
 * 创建时间：2016年11月9日 下午4:16:32
 *
 * @author andy
 * @version 2.2
 */
public class HttpUtils {

  private static final String DEFAULT_CHARSET = "UTF-8";

  private static final int CONNECT_TIME_OUT = 5000; // 链接超时时间3秒

  private static final RequestConfig REQUEST_CONFIG =
      RequestConfig.custom().setConnectTimeout(CONNECT_TIME_OUT).build();

  private static SSLContext wx_ssl_context = null; // 微信支付ssl证书
  private static Logger log = LoggerFactory.getLogger(HttpUtils.class);

  /*static{
  	Resource resource = new ClassPathResource("wx_apiclient_cert.p12");
  	try {
  		KeyStore keystore = KeyStore.getInstance("PKCS12");
  		char[] keyPassword = ConfigUtil.getProperty("wx.mchid").toCharArray(); //证书密码
  		keystore.load(resource.getInputStream(), keyPassword);
  		wx_ssl_context = SSLContexts.custom().loadKeyMaterial(keystore, keyPassword).build();
  	} catch (Exception e) {
  		e.printStackTrace();
  	}
  }*/

  /**
   * @description 功能描述: get 请求
   * @param url 请求地址
   * @param params 参数
   * @param headers headers参数
   * @return 请求失败返回null
   */
  public static String get(String url, Map<String, String> params, Map<String, String> headers) {

    CloseableHttpClient httpClient = null;
    if (params != null && !params.isEmpty()) {
      StringBuffer param = new StringBuffer();
      boolean flag = true; // 是否开始
      for (Entry<String, String> entry : params.entrySet()) {
        if (flag) {
          param.append("?");
          flag = false;
        } else {
          param.append("&");
        }
        param.append(entry.getKey()).append("=");

        try {
          param.append(URLEncoder.encode(entry.getValue(), DEFAULT_CHARSET));
        } catch (UnsupportedEncodingException e) {
          // 编码失败
        }
      }
      url += param.toString();
    }

    String body = null;
    CloseableHttpResponse response = null;
    try {
      httpClient = HttpClients.custom().setDefaultRequestConfig(REQUEST_CONFIG).build();
      HttpGet httpGet = new HttpGet(url);
      response = httpClient.execute(httpGet);
      body = EntityUtils.toString(response.getEntity(), DEFAULT_CHARSET);
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      if (response != null) {
        try {
          response.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }

      if (httpClient != null) {
        try {
          httpClient.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
    return body;
  }

  /**
   * @description 功能描述: get 请求
   * @param url 请求地址
   * @return 请求失败返回null
   */
  public static String get(String url) {
    return get(url, null);
  }

  /**
   * @description 功能描述: get 请求
   * @param url 请求地址
   * @param params 参数
   * @return 请求失败返回null
   */
  public static String get(String url, Map<String, String> params) {
    return get(url, params, null);
  }

  /**
   * @description 功能描述: post 请求
   * @param url 请求地址
   * @param params 参数
   * @return 请求失败返回null
   */
  public static String post(String url, Map<String, String> params) {
    CloseableHttpClient httpClient = null;
    HttpPost httpPost = new HttpPost(url);
    List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
    if (params != null && !params.isEmpty()) {
      for (Entry<String, String> entry : params.entrySet()) {
        nameValuePairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
      }
    }

    String body = null;
    CloseableHttpResponse response = null;
    try {
      httpClient = HttpClients.custom().setDefaultRequestConfig(REQUEST_CONFIG).build();
      httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, DEFAULT_CHARSET));
      response = httpClient.execute(httpPost);
      body = EntityUtils.toString(response.getEntity(), DEFAULT_CHARSET);
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      if (response != null) {
        try {
          response.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }

      if (httpClient != null) {
        try {
          httpClient.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
    return body;
  }

  /**
   * @description 功能描述: post 请求
   * @param url 请求地址
   * @param s 参数xml
   * @return 请求失败返回null
   */
  public static String post(String url, String s) {
    CloseableHttpClient httpClient = null;
    HttpPost httpPost = new HttpPost(url);
    String body = null;
    CloseableHttpResponse response = null;
    try {
      httpClient = HttpClients.custom().setDefaultRequestConfig(REQUEST_CONFIG).build();
      httpPost.setEntity(new StringEntity(s, DEFAULT_CHARSET));
      response = httpClient.execute(httpPost);
      body = EntityUtils.toString(response.getEntity(), DEFAULT_CHARSET);
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      if (response != null) {
        try {
          response.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }

      if (httpClient != null) {
        try {
          httpClient.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
    return body;
  }

  /**
   * @description 功能描述: post https请求，服务器双向证书验证
   * @param url 请求地址
   * @param params 参数
   * @return 请求失败返回null
   */
  public static String posts(String url, Map<String, String> params) {
    CloseableHttpClient httpClient = null;
    HttpPost httpPost = new HttpPost(url);
    List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
    if (params != null && !params.isEmpty()) {
      for (Entry<String, String> entry : params.entrySet()) {
        nameValuePairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
      }
    }

    String body = null;
    CloseableHttpResponse response = null;
    try {
      httpClient =
          HttpClients.custom()
              .setDefaultRequestConfig(REQUEST_CONFIG)
              .setSSLSocketFactory(getSSLConnectionSocket())
              .build();
      httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, DEFAULT_CHARSET));
      response = httpClient.execute(httpPost);
      body = EntityUtils.toString(response.getEntity(), DEFAULT_CHARSET);
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      if (response != null) {
        try {
          response.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }

      if (httpClient != null) {
        try {
          httpClient.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
    return body;
  }

  /**
   * @description 功能描述: post https请求，服务器双向证书验证
   * @param url 请求地址
   * @param s 参数xml
   * @return 请求失败返回null
   */
  public static String posts(String url, String s) {
    CloseableHttpClient httpClient = null;
    HttpPost httpPost = new HttpPost(url);
    String body = null;
    CloseableHttpResponse response = null;
    try {
      httpClient =
          HttpClients.custom()
              .setDefaultRequestConfig(REQUEST_CONFIG)
              .setSSLSocketFactory(getSSLConnectionSocket())
              .build();
      httpPost.setEntity(new StringEntity(s, DEFAULT_CHARSET));
      response = httpClient.execute(httpPost);
      body = EntityUtils.toString(response.getEntity(), DEFAULT_CHARSET);
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      if (response != null) {
        try {
          response.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }

      if (httpClient != null) {
        try {
          httpClient.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
    return body;
  }

  // 获取ssl connection链接
  private static SSLConnectionSocketFactory getSSLConnectionSocket() {
    return new SSLConnectionSocketFactory(
        wx_ssl_context,
        new String[] {"TLSv1", "TLSv1.1", "TLSv1.2"},
        null,
        SSLConnectionSocketFactory.getDefaultHostnameVerifier());
  }

  /**
   * 发送post请求
   *
   * @param url 请求地址
   * @param outputEntity 发送内容
   * @param isLoadCert 是否加载证书
   */
  public static CloseableHttpResponse Post(
      String url, String outputEntity, String mch_id, String certUrl, boolean isLoadCert)
      throws Exception {
    HttpPost httpPost = new HttpPost(url);
    // 得指明使用UTF-8编码，否则到API服务器XML的中文不能被成功识别
    httpPost.addHeader("Content-Type", "text/xml");
    httpPost.setEntity(new StringEntity(outputEntity, "UTF-8"));
    if (isLoadCert) {
      // 加载含有证书的http请求
      return HttpClients.custom()
          .setSSLSocketFactory(CertUtil.initCert(mch_id, certUrl))
          .build()
          .execute(httpPost);
    } else {
      return HttpClients.custom().build().execute(httpPost);
    }
  }

  /** ----------------------------------------------------- */
  private static StringEntity createEntry(String requestStr) {
    return new StringEntity(requestStr, ContentType.create("application/json", "utf-8"));
    // return new StringEntity(new String(requestStr.getBytes(StandardCharsets.UTF_8),
    // StandardCharsets.ISO_8859_1));
  }

  private static HttpPost createHttpPost(String url, String requestStr) {
    HttpPost httpPost = new HttpPost(url);
    httpPost.setEntity(createEntry(requestStr));

    httpPost.setConfig(
        RequestConfig.custom()
            .setConnectionRequestTimeout(5000)
            .setConnectTimeout(5000)
            .setSocketTimeout(10000)
            .build());

    return httpPost;
  }

  public static String postV3(String url, String requestStr, HttpClient client) {
    CloseableHttpClient httpClient = (CloseableHttpClient) client;
    HttpPost httpPost = createHttpPost(url, requestStr);
    httpPost.addHeader("Accept", "application/json");
    httpPost.addHeader("Content-Type", "application/json");
    try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
      // v3已经改为通过状态码判断200 204 成功
      int statusCode = response.getStatusLine().getStatusCode();
      String responseString = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
      if (HttpStatus.SC_OK == statusCode || HttpStatus.SC_NO_CONTENT == statusCode) {
        log.info("\n【请求地址】：{}\n【请求数据】：{}\n【响应数据】：{}", url, requestStr, responseString);
        return responseString;
      } else {
        // 有错误提示信息返回
        JSONObject jsonObject = JSONUtil.parseObj(responseString);
        throw new RuntimeException(jsonObject.getStr("message"));
      }
    } catch (Exception e) {
      log.error("\n【请求地址】：{}\n【请求数据】：{}\n【异常信息】：{}", url, requestStr, e.getMessage());
      throw new RuntimeException(e.getMessage());
    } finally {
      httpPost.releaseConnection();
    }
  }
}
